﻿/*
SINACOR - BMF&Bovespa
Arquivo: MonitorAlocacao.cs
Criado em: 30-mar-2010 15:39:46
Arquiteto Responsável: RAMelo.7Comm
*/
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Timers;

using Sinacor.Infra.Common;
using Sinacor.Infra.UI.Common;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.UI.Authorization;
using Sinacor.Infra.Core.ProcessManager.Client;
using Sinacor.Infra.Service.Security.Authorization;

using Sinacor.UI.Bovespa.Alocacao.Model;
using Sinacor.UI.Bovespa.Alocacao.Communication.Bovespa.Calendario;
using Sinacor.UI.Bovespa.Alocacao.Communication.Bovespa.Alocacao.MonitorAlocacao;

using PSE.ProcessManager.Common.Process;
using PSE.ProcessManager.Client.Process;

namespace Sinacor.UI.Bovespa.Alocacao.Presenter 
{
    public class MonitorAlocacao : AlocacaoBase<IMonitorAlocacao>
    {
        #region Atributos

		private Communication.MensagensAlocacao _communicationMensagensAlocacao;
		private Communication.MonitorAlocacao _communicationMonitorAlocacao;

		private Model.Parameter.FiltroMonitorAlocacao _filtroMonitorAlocacao;
        private Model.TotalizadorMensagensAlocacao _totalizador;

		private ModelCollection<Model.ErroAlocacao> _listaErrosAlocacao;
		private ModelCollection<Model.MensagemAlocacao> _listaMensagensAlocacao;
        private ModelCollection<Model.MensagemAlocacao> _listaMensagensAlocacaoOriginal;
		private ModelCollection<Model.MensagemAlocacaoRealizada> _listaMensagensAlocacaoRealizada;
        private ObservableCollection<EnumWrapper<Model.Enum.TipoMercado>> _listaTiposMercado;

        private Timer _temporizadorMensagensAlocacao;
		
		private bool _tratarOrdensDiscricionariasNaoDistribuidas;
        private bool _indicadorExecutaProcesso = false;

		#endregion

		#region Propriedades

        /// <summary>
        /// Irá armazenar os dados de filtro da pesquisa de mensagens de alocação
        /// </summary>
        public Model.Parameter.FiltroMonitorAlocacao FiltroMonitorAlocacao
        {
            get { return this._filtroMonitorAlocacao; }
            set { this._filtroMonitorAlocacao = value; }
        }       

		/// <summary>
		/// Lista que irá armazenar o resultado da consulta de erros de alocação (Binding
		/// com datagrid de Erros)
		/// </summary>
		public ModelCollection<Model.ErroAlocacao> ListaErrosAlocacao
		{
            get { return this._listaErrosAlocacao; }
            set { this._listaErrosAlocacao = value; }
		}

		/// <summary>
		/// Lista que irá armazenar o resultado da consulta de mensagens de alocação
		/// (Binding com datagrid de Mensagens)
		/// </summary>
		public ModelCollection<Model.MensagemAlocacao> ListaMensagensAlocacao
		{
            get { return this._listaMensagensAlocacao; }
            set { this._listaMensagensAlocacao = value; }
		}

        /// <summary>
        /// Lista que irá armazenar a copia da lista de ListaMensagensAlocacao
        /// </summary>
        public ModelCollection<Model.MensagemAlocacao> ListaMensagensAlocacaoOriginal
        {
            get { return this._listaMensagensAlocacaoOriginal; }
            set { this._listaMensagensAlocacaoOriginal = value; }
        }

		/// <summary>
		/// Lista que irá armazenar o resultado da consulta de alocações realizadas
		/// (Binding com datagrid de Alocação)
		/// </summary>
		public ModelCollection<Model.MensagemAlocacaoRealizada> ListaMensagensAlocacaoRealizada
		{
            get { return this._listaMensagensAlocacaoRealizada; }
            set { this._listaMensagensAlocacaoRealizada = value; }
		}

		/// <summary>
		/// Binding com o combobox de mercados
		/// </summary>
        public ObservableCollection<EnumWrapper<Model.Enum.TipoMercado>> ListaTiposMercado
		{
            get { return this._listaTiposMercado; }
            set { this._listaTiposMercado = value; }
		}

		/// <summary>
		/// Binding com os textbox´s que apresentam os totais de cada tipo de mensagem
		/// </summary>
        public Model.TotalizadorMensagensAlocacao Totalizador
        {
            get { return this._totalizador; }
            set { this._totalizador = value; }
        }

		#endregion

        #region Construtor

        /// <summary>
        /// Construtor padrão
        /// </summary>
        public MonitorAlocacao(IMonitorAlocacao view)
            : base(view)
        {                                   
            this._communicationMensagensAlocacao = new Communication.MensagensAlocacao(this.Session);
            this._communicationMonitorAlocacao = new Communication.MonitorAlocacao(this.Session);

            this.FiltroMonitorAlocacao = new Model.Parameter.FiltroMonitorAlocacao();
            this.Totalizador = new Model.TotalizadorMensagensAlocacao();

            this.ListaErrosAlocacao = new ModelCollection<Model.ErroAlocacao>();
            this.ListaMensagensAlocacao = new ModelCollection<Model.MensagemAlocacao>();
            this.ListaMensagensAlocacaoOriginal = new ModelCollection<Model.MensagemAlocacao>();
            this.ListaMensagensAlocacaoRealizada = new ModelCollection<Model.MensagemAlocacaoRealizada>();
            this.InformacoesMovimento = new InformacoesMovimento();
            this.ListaTiposMercado = new ObservableCollection<EnumWrapper<Model.Enum.TipoMercado>>();

            this._communicationMensagensAlocacao.CommunicationError += new EventHandler<CommunicationErrorEventArgs>(CommunicationError);

            this._temporizadorMensagensAlocacao = new Timer();
            this._temporizadorMensagensAlocacao.Elapsed += new ElapsedEventHandler(Elapsed);            
            this._temporizadorMensagensAlocacao.Enabled = false;
        }

        #endregion

		#region Métodos

        #region ProcessMenager

        /// <summary>
        /// Evento para tratamento de erros no processo de geração de alocações
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CommunicationError(object sender, CommunicationErrorEventArgs e)
        {
            try
            {
                if (e.Exception is BusinessException || e.Exception is ValidationException)
                {
                    base.HandleException(e.Exception);
                }
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
        }
        
        #endregion        

        #region Configurar Temporizador de Mensagens de Alocação

        /// <summary>
		/// Configura o timer que irá ficar consultando as mensagens de alocação
		/// </summary>
		public void ConfigurarTemporizadorMensagensAlocacao()
		{
            if (this.FiltroMonitorAlocacao.TempoExecucao.HasValue && this.FiltroMonitorAlocacao.TempoExecucao.Value != 0)
            {
                this._temporizadorMensagensAlocacao.Interval = new TimeSpan(0, this.FiltroMonitorAlocacao.TempoExecucao.Value, 0).TotalMilliseconds;
                this._temporizadorMensagensAlocacao.Enabled = true;
                this._temporizadorMensagensAlocacao.Start();

                this.View.VisualizarMenuInterromperEnvioMensagens(true);
            }
		}

        /// <summary>
        /// Evento elapsed do temporizador
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                this.ConsultarMensagensAlocacao();
                this.EnviarAlocacoes(this._tratarOrdensDiscricionariasNaoDistribuidas);
            }
            catch (Exception ex)
            {
                HandleException(ex);
            }
        }

        #endregion

        #region Consultar Alocações Realizadas

        /// <summary>
		/// Consulta as alocações realizadas
		/// </summary>
		/// <param name="mensagem"></param>
		public void ConsultarAlocacoesRealizadas(Model.MensagemAlocacao mensagem)
		{
            try
            {
                Model.Parameter.FiltroAlocacao filtroAlocacao = new Model.Parameter.FiltroAlocacao
                {
                    DataPregao = (mensagem.DataPregao.HasValue ? mensagem.DataPregao.Value : new DateTime()),
                    NumeroMensagem = (mensagem.Sequencia.HasValue ? mensagem.Sequencia.Value : 0)
                };

                this.ListaMensagensAlocacaoRealizada = this._communicationMonitorAlocacao.ConsultarAlocacoesRealizadas(filtroAlocacao);
                this.View.AtualizarAlocacoesRealizadas();
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
        }

        #endregion

        #region Consultar Erros de Alocação

        /// <summary>
		/// Consulta os erros de alocações
		/// </summary>
		/// <param name="mensagem"></param>
		public void ConsultarErrosAlocacao(Model.MensagemAlocacao mensagem)
		{
            try
            {
                if ((mensagem.Estado == Model.Enum.EstadoMensagemAlocacao.Falha) || (mensagem.Estado == Model.Enum.EstadoMensagemAlocacao.FalhaTratada))
                {
                    Model.Parameter.FiltroAlocacao filtroAlocacao = new Model.Parameter.FiltroAlocacao
                    {
                        DataPregao = (mensagem.DataPregao.HasValue ? mensagem.DataPregao.Value : new DateTime()),
                        NumeroMensagem = (mensagem.Sequencia.HasValue ? mensagem.Sequencia.Value : 0)
                    };

                    this.ListaErrosAlocacao = this._communicationMonitorAlocacao.ConsultarErrosAlocacao(filtroAlocacao);

                    this.View.AtualizarErrosAlocacao();
                    this.View.HabilitarMenuTratarFalha(true);
                    this.View.HabilitarMenuReenviarMensagem(true);
                }
                else
                {
                    this.View.HabilitarMenuTratarFalha(false);
                    this.View.HabilitarMenuReenviarMensagem(false);
                }
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
		}

        #endregion

        #region Consultar Mensagens de Alocação

        /// <summary>
		/// Consulta as mensagens de alocação
		/// </summary>
		public void ConsultarMensagensAlocacao()
		{
            try
            {
                this.ListaMensagensAlocacaoOriginal = this._communicationMonitorAlocacao.ConsultarMensagensAlocacao(this.FiltroMonitorAlocacao);

                this.ConfigurarTemporizadorMensagensAlocacao();

                if (this.FiltroMonitorAlocacao.Estado != null)
                {
                    this.FiltrarMensagens(this.FiltroMonitorAlocacao.Estado);
                }
                else
                {
                    this.ListaMensagensAlocacao = (ModelCollection<Model.MensagemAlocacao>)Infra.Common.Serialization.CloneHelper.Clone(this.ListaMensagensAlocacaoOriginal);
                    this.View.AtualizarMensagensAlocacao();
                }

                this.TotalizarMensagensAlocacao();
            }
            catch (Exception ex)
            {                
                base.HandleException(ex);
            } 
        }

        #endregion

        #region Carregar Enum

        /// <summary>
        /// Responsável por popular a ListaTiposMercado com todos os tipo de mercado.
        /// </summary>
        public void CarregarTipoMercado()
        {
            this.ListaTiposMercado = EnumWrapper<Model.Enum.TipoMercado>.GetEnums(Model.Enum.TipoMercado.BOX,
                                                                                  Model.Enum.TipoMercado.CotasETF,
                                                                                  Model.Enum.TipoMercado.Estruturado,
                                                                                  Model.Enum.TipoMercado.ExercicioOpcaoCompra,
                                                                                  Model.Enum.TipoMercado.ExercicioOpcaoVenda,
                                                                                  Model.Enum.TipoMercado.Fracionario,
                                                                                  Model.Enum.TipoMercado.Futuro,
                                                                                  Model.Enum.TipoMercado.IntegralizacaoResgateCotas,
                                                                                  Model.Enum.TipoMercado.Leilao,
                                                                                  Model.Enum.TipoMercado.LeilaoNaoCotados,
                                                                                  Model.Enum.TipoMercado.OpcaoCompra,
                                                                                  Model.Enum.TipoMercado.OpcaoVenda,
                                                                                  Model.Enum.TipoMercado.OpcaoVendaCompra,
                                                                                  Model.Enum.TipoMercado.Termo,
                                                                                  Model.Enum.TipoMercado.VencimentoFuturo,
                                                                                  Model.Enum.TipoMercado.Vista);
        }

        #endregion

        #region Enviar Alocações

        /// <summary>
		/// Executa a geração de alocações
		/// </summary>
		/// <param name="tratarOrdensDiscricionariasNaoDistribuidas"></param>
		private void EnviarAlocacoes(bool tratarOrdensDiscricionariasNaoDistribuidas)
		{
            if (this._indicadorExecutaProcesso)
            {
                if (!this._communicationMensagensAlocacao.IsProcessRunning())
                {
                    Model.DadosExecucao dadosExecucao = new DadosExecucao
                    {
                        OrdensDiscricionariasNaoDistribuidas = tratarOrdensDiscricionariasNaoDistribuidas
                    };

                    this._communicationMensagensAlocacao.Execute(dadosExecucao);
                }
            }
        }

        #endregion

        #region Filtrar Mensagens

        /// <summary>
		/// Filtra as mensagens á partir do estado informado como parâmetro
		/// </summary>
		/// <param name="estado"></param>
		public void FiltrarMensagens(EnumWrapper<Model.Enum.EstadoMensagemAlocacao> estado)
		{
            if (estado != null)
            {
                List<Model.MensagemAlocacao> aux = this.ListaMensagensAlocacaoOriginal.ToList().FindAll(item => item.Estado == estado);

                this.ListaMensagensAlocacao.EnableStateControl = false;

                this.ListaMensagensAlocacao.Clear();

                foreach (var item in aux)
                {
                    this.ListaMensagensAlocacao.Add(item);
                }

                this.ListaMensagensAlocacao.EnableStateControl = true;                
            }
            else
            {
                this.ListaMensagensAlocacao = (ModelCollection<Model.MensagemAlocacao>)Infra.Common.Serialization.CloneHelper.Clone(this.ListaMensagensAlocacaoOriginal);
            }

            this.View.AtualizarMensagensAlocacao();
        }

        #endregion

        #region Inicializar

        /// <summary>
		/// Inicializa a aba de mensagens de alocação
		/// </summary>
		public void Inicializar()
		{
            try
            {
                this.ConsultarCalendarios();

                this.CarregarTipoMercado();

                ModelCollection<Model.Calendario> calendarios = (ModelCollection<Model.Calendario>)Infra.Common.Serialization.CloneHelper.Clone(base.ListaCalendarios);  

                if (base.ListaCalendarios.Count > 0)
                {
                    var aux = (from c in calendarios
                                      orderby c.DataPregao descending
                                      select c).Take(2);

                    base.ListaCalendarios.Clear();

                    foreach (var item in aux)
                    {
                        base.ListaCalendarios.Add(item);
                    }
                }

                this.ObterInformacoesMovimento();

                this.View.AtualizarListaCalendarios();
                this.View.AtribuirDataMovimento();
                
                this.ValidarPermissaoAcesso();                
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
        }

        #endregion

        #region Iniciar o Envio de Mensagens de Alocação

        /// <summary>
		/// Inicia a execução do processo de geração e envio de mensagens de alocação
		/// </summary>
		/// <param name="tratarOrdensDiscricionariasNaoDistribuidas"></param>
		public void IniciarEnvioMensagensAlocacao(bool tratarOrdensDiscricionariasNaoDistribuidas)
		{
            try
            {
                if (this.View.ConfirmarEnvioAlocacoes())
                {
                    this._tratarOrdensDiscricionariasNaoDistribuidas = tratarOrdensDiscricionariasNaoDistribuidas;
                    this._indicadorExecutaProcesso = true;

                    this.View.VisualizarMenuEnviarMensagensAlocacao(!this.HabilitaMenuInterromper());
                    this.View.VisualizarMenuInterromperEnvioMensagens(this.HabilitaMenuInterromper());
                    
                    this.EnviarAlocacoes(tratarOrdensDiscricionariasNaoDistribuidas);
                }
                else
                {
                    this.View.VisualizarMenuEnviarMensagensAlocacao(true);
                    this.View.VisualizarMenuInterromperEnvioMensagens(false);
                }
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
        }

        #endregion

        #region Interromper o Envio de Alocações

        /// <summary>
		/// Interrompe a chamada para o processo de geração e envio de mensagens de
		/// alocação
		/// </summary>
		public void InterromperEnvioAlocacoes()
		{
            this._indicadorExecutaProcesso = false;

            this.View.VisualizarMenuEnviarMensagensAlocacao(true);
            this.View.VisualizarMenuInterromperEnvioMensagens(false);
        }

        #endregion

        #region Parar o Temporizador

        /// <summary>
		/// Interrompe o temporizador de mensagens alocação
		/// </summary>
		public void PararTemporizador()
		{
			this._temporizadorMensagensAlocacao.Stop();
        }

        #endregion

        #region Reenviar a Mensagem de Alocação

        /// <summary>
		/// Realiza o reenvio das mensagens informadas como parâmetro de entrada
		/// </summary>
		/// <param name="mensagem"></param>
		/// <param name="tratarOrdensDiscricionariasNaoDistribuidas"></param>
		public Model.ResultadoReenvio ReenviarMensagemAlocacao(Model.MensagemAlocacao mensagem, bool tratarOrdensDiscricionariasNaoDistribuidas)
		{
            Model.ResultadoReenvio resultado = null;

            try
            {
                resultado = new ResultadoReenvio();

                if ((mensagem.Estado == Model.Enum.EstadoMensagemAlocacao.Falha) || (mensagem.Estado == Model.Enum.EstadoMensagemAlocacao.FalhaTratada))
                {
                    Model.DadosReenvioMensagemAlocacao dadosReenvioMensagem = new DadosReenvioMensagemAlocacao
                    {
                        Mensagem = mensagem,
                        OrdensDiscricionariasNaoDistribuidas = tratarOrdensDiscricionariasNaoDistribuidas
                    };

                    resultado = this._communicationMonitorAlocacao.ReenviarMensagemAlocacao(dadosReenvioMensagem);

                    resultado.Status = mensagem.InformacoesRetorno;
                }                
            }
            catch (Exception ex)
            {
                base.HandleException(ex);    
            }

            return resultado;
        }

        #endregion

        #region Totalizar as Mensagens de Alocação

        /// <summary>
		/// Totaliza por tipo de mensagem o resultado da pesquisa de mensagens de alocação
		/// </summary>
		private void TotalizarMensagensAlocacao()
		{
            this.Totalizador.Geradas = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.Gerada);

            this.Totalizador.FilaEnvio = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.FilaEnvio);

            this.Totalizador.Invalidadas = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.Invalidada);

            this.Totalizador.ProcessandoRetorno = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.ProcessandoRetorno);

            this.Totalizador.Aceitas = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.Aceita);

            this.Totalizador.Falhas = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.Falha);

            this.Totalizador.FalhasTratadas = this.ListaMensagensAlocacaoOriginal.Count(item => item.Estado == Model.Enum.EstadoMensagemAlocacao.FalhaTratada);

            this.Totalizador.TodasMensagens = this.ListaMensagensAlocacaoOriginal.Count();

            this.View.AtualizarTotalizadores();
        }

        #endregion

        #region Tratar as Mensagens Falhas

        /// <summary>
		/// Realiza o tratamento de mensagens com falhas
		/// </summary>
		/// <param name="mensagens"></param>
		public void TratarMensagensFalhas(ModelCollection<Model.MensagemAlocacao> mensagens)
		{
            try
            {
                if (this.View.ConfirmarTratamentoFalhas())
                {
                    this._communicationMonitorAlocacao.TratarMensagensFalhas(mensagens);
                }
            }
            catch (Exception ex)
            {
                base.HandleException(ex);
            }
        }

        #endregion

        #region Validar a Permissão de Acesso

        /// <summary>
		/// Valida a permissão de acesso do usuário logado
		/// </summary>
		private void ValidarPermissaoAcesso()
		{
            AuthorizationManager authorizationManager = AuthorizationManager.GetInstance();

            if (!authorizationManager.CheckUserAccess("ORD", "ORDM"))
            {
                this.View.DesabilitarMenuMensagensAlocacao();
                this.View.InformarUsuarioSemPermissao();
            }
            else
            {
                if (base.InformacoesMovimento.EstadoMovimento != Model.Enum.TipoMovimento.Abertura)
                {
                    this.View.DesabilitarMenuMensagensAlocacao();
                    this.View.InformarMovimentoOrdemNaoAberto();
                }
            }
        }

        #endregion

        #region Verificar o Estado da Mensagem

        /// <summary>
		/// Verifica qual o estado da mensagem e atribui qual a cor deverá ser aplicada na
		/// linha da datagrid de mensagens de alocação
		/// </summary>
		/// <param name="mensagem"></param>
		public void VerificarEstadoMensagem(Model.MensagemAlocacao mensagem)
		{
            if (mensagem.Estado != null)
            {
                switch (mensagem.Estado.Value)
                {
                    case Model.Enum.EstadoMensagemAlocacao.Aceita:
                        this.View.ApresentarMensagemAceita();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.Falha:
                        this.View.ApresentarMensagemFalha();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.FalhaTratada:
                        this.View.ApresentarMensagemFalhaTratada();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.FilaEnvio:
                        this.View.ApresentarMensagemFilaEnvio();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.Gerada:
                        this.View.ApresentarMensagemGerada();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.Invalidada:
                        this.View.ApresentarMensagemInvalidada();
                        break;
                    case Model.Enum.EstadoMensagemAlocacao.ProcessandoRetorno:
                        this.View.ApresentarMensagemProcessandoRetorno();
                        break;
                }
            }
        }

		#endregion

        #region Limpar filtro de pesquisa

        /// <summary>
        /// Atribuir a todas as propriedades valores nulos.
        /// </summary>
        public void LimparFiltroPesquisa()
        {
            this.FiltroMonitorAlocacao.ApelidoCliente = string.Empty;
            this.FiltroMonitorAlocacao.Ativo = string.Empty;
            this.FiltroMonitorAlocacao.CodigoCliente = null;
            this.FiltroMonitorAlocacao.DataPregao = null;
            this.FiltroMonitorAlocacao.Estado = null;
            this.FiltroMonitorAlocacao.Mercado = null;
            this.FiltroMonitorAlocacao.NaturezaOperacao = Model.Enum.NaturezaOperacao.CompraVenda;
            this.FiltroMonitorAlocacao.NumeroNegocio = null;
            this.FiltroMonitorAlocacao.TempoExecucao = null;

            this.View.AtualizarPesquisa();
        }

        #endregion

        #region Zerar o contador

        /// <summary>
        /// Atribuir a todas as propriedades valores nulos.
        /// </summary>
        public void ZerarContador()
        {
            this.Totalizador.Geradas = null;
            this.Totalizador.FilaEnvio = null;
            this.Totalizador.Invalidadas = null;
            this.Totalizador.ProcessandoRetorno = null;
            this.Totalizador.Aceitas = null;
            this.Totalizador.Falhas = null;
            this.Totalizador.FalhasTratadas = null;
            this.Totalizador.TodasMensagens = null;

            this.View.AtualizarTotalizadores();
        }

        #endregion

        #region Habilita o menu Interromper

        private bool HabilitaMenuInterromper()
        {
            return this._temporizadorMensagensAlocacao.Enabled;
        }

        #endregion

        #endregion
    }

}